Blog

CSS-in-JS mit dem brandneuen StyleX

Feb 20, 2024

CSS ist für viele Webentwickler:innen ein Buch mit sieben Siegeln. Wir zimmern das Stylesheet so hin, dass es passt, und hoffen, dass nicht zu viele Änderungswünsche kommen, die das fragile Gebilde zum Einsturz bringen. Die Situation wird noch schlimmer, wenn verschiedene Breakpoints im Spiel sind. Aber irgendwie hat sich daraus eine gewisse Hassliebe entwickelt. Ganz ohne Styling geht es ja schließlich auch nicht. Mit einem gut designten API lassen sich unsere Benutzer:innen leider nicht wirklich beeindrucken. Also sollten wir uns das Leben so einfach und angenehm wie möglich gestalten.

Dafür gibt es zahlreiche Hilfsmittel wie Präprozessoren wie Sass. Dann sind da noch ganz andere Lösungsansätze wie das Utility-First-Framework Tailwind, bei dem Kritiker oft anführen, dass es aussieht, als würde man Inline Styles mit CSS-Klassen schreiben. Doch das sind nicht die einzigen Möglichkeiten. Welche weiteren für das Styling noch verfügbar sind, hängt ganz stark von der jeweiligen Umgebung ab. Heute werfen wir einmal einen genaueren Blick auf das Styling mit React, weil es da wieder einmal größere Neuigkeiten gibt. Facebook hat sein Styling-System StyleX Open Source gestellt und damit ein weiteres CSS-in-JS-Werkzeug auf den Markt gebracht. Dies ist eine hervorragende Gelegenheit, einen genaueren Blick auf diese Styling-Variante zu werfen.

Doch bevor wir nun mit CSS-in-JS loslegen, sehen wir uns die übrigen Styling-Möglichkeiten einer typischen React-Applikation an. Wobei mittlerweile auch der Begriff einer „typischen React-Applikation“ nicht mehr so eindeutig ist. Geht es nach dem React-Team und der offiziellen Doku, müssten wir hier von einer Next.js-Applikation sprechen. Eine rein clientseitige React-Applikation ist jedoch weiterhin auch ohne ein Fullstack-Framework möglich, nur sollten Sie hierfür nicht mehr auf das totgesagte Create React App setzen, sondern doch besser ein moderneres Werkzeug wie Vite nutzen. Generell ist es jedoch egal, welche Umgebung Sie nutzen, denn in Sachen Styling sind sie alle gleich. Die folgenden Optionen stehen Ihnen zur Verfügung:

  • Globale Styles: Die einfachste Variante besteht darin, CSS ganz regulär in das HTML-Dokument der Applikation zu integrieren. Entweder über ein externes Stylesheet oder ein style-Tag. Dieses Styling gilt applikationsweit, verfügt über keinerlei Namespacing, außer Sie implementieren es selbst, und glänzt auch nicht mit Wiederverwendbarkeit.

  • CSS-Importe: Die meisten React-Umgebungen wie Vite, aber auch Next.js, unterstützten den Import von CSS-Dateien in JavaScript. Dabei nutzen Sie das ECMAScript-Modulsystem, nur dass Sie CSS- statt JavaScript-Dateien importieren. Hier gelten die gleichen Einschränkungen wie bei den globalen Styles. Sie müssen also sehr behutsam vorgehen, damit importierte Stylesheets sich nicht plötzlich auf andere Teile oder gar die gesamte Applikation auswirken.

  • CSS-Module: Deutlich besser wird die Situation mit CSS-Modulen. Hier schreiben Sie auch gewöhnlichen CSS-Code, müssen sich aber auf Klassenselektoren beschränken. Dafür sorgen die CSS-Module dafür, dass die Selektoren sich nur auf Ihre aktuelle Komponente und nicht auf die gesamte Applikation auswirken.

  • CSS-Frameworks: In letzter Zeit haben CSS-Frameworks wie Tailwind erheblich an Popularität gewonnen. Sie sind zum einen sehr mächtig und arbeiten auf Basis von CSS. Dieser Aspekt ist gerade in Richtung Fullstack-Frameworks wichtig, da sich statische Stylesheets deutlich besser handeln und vorgenerieren lassen als dynamischer Code.

  • CSS-in-JS: Der CSS-in-JS-Ansatz kommt vor allem JavaScript-Entwickler:innen entgegen. Hier müssen Sie zwar immer noch CSS schreiben, der Code ist jedoch in JavaScript eingebettet. Sie können den Funktionsumfang von CSS mit JavaScript erweitern und sogar Logik und Parametrisierung in den Styles implementieren. Bei allen Vorteilen gibt es bei CSS-in-JS-Lösungen teilweise Probleme im Zusammenhang mit Fullstack-Frameworks wie Next.js.

LUST AUF NOCH MEHR HTML & CSS?

Entdecken Sie Workshops vom 21. - 24. Oktober 2024

 

Populäre Vertreter von CSS-in-JS-Lösungen sind die Bibliotheken Styled-Components oder Emotion. In Listing 1 sehen Sie ein Beispiel für den Einsatz von Styled-Components.

Listing 1: Styling eines button-Elements mit Styled-Components

const Button = styled.button`
  background-color: #4caf50;
  color: white;
  padding: 10px 20px;
  border: none;
  border-radius: 5px;
  cursor: pointer;
  font-size: 16px;
  transition: background-color 0.3s;
 
  &:hover {
    background-color: #45a049; 
  }
`;

Das Ergebnis einer solchen Styled-Component ist eine Komponente, die das Element, in diesem Fall einen Button, mit den Styles kombiniert. Sie können diese Komponenten wie gewöhnliche Komponenten benutzen. Alle Props des ursprünglichen Elements stehen Ihnen auch in der Styled-Component zur Verfügung, sodass Sie beispielsweise auf einen Klick auf den Button mit der onClick-Prop reagieren können.

StyleX – das Style-System von Facebook

In letzter Zeit war es eher ruhig in der CSS-in-JS-Welt, doch plötzlich sorgt eine Veröffentlichung für Aufsehen. Im November 2023 hat Facebook StyleX veröffentlicht, eine JavaScript-Bibliothek, um Styles für optimierte User Interfaces zu definieren, das sagt zumindest die Dokumentation des Projekts. Doch was steckt dahinter? Zunächst ist StyleX die Styling-Bibliothek hinter Facebook, Instagram, WhatsApp und Threads. Klingt verdächtig nach React? Richtig! Meta setzt StyleX auf seinen großen React-Plattformen ein, und das nicht erst seit Ende November 2023. Dieser Zeitpunkt war der erste öffentliche Commit in das GitHub-Repo des Projekts. Davor kam die Bibliothek schon längere Zeit intern zum Einsatz. Es ist also keine Beta-Software, sondern vielmehr eine zigfach getestete Lösung, die das Entwicklerteam jetzt auf den Markt wirft. Werfen wir also einen Blick auf die Bibliothek und auf die Aspekte, die sie von anderen ähnlichen Lösungen unterscheidet. Laut Dokumentation verfolgt StyleX eine ganze Reihe von Prinzipien:

  • Co-Location: Die Styles sollen dort liegen, wo sie angewendet werden.

  • Deterministic Resolution: Die Styles von StyleX sollen vorhersehbar sein, auch über Dateigrenzen hinweg: „The last style applied always wins“ – Der zuletzt angewendete Style gewinnt immer.

  • Low-cost abstraction: StyleX versucht immer, die schnellstmögliche Lösung zu bieten. Standardfälle verursachen keine Laufzeitkosten. Das Definieren und Anwenden von Styles in einer Datei bringt keinen zusätzlichen Overhead mit sich. Verwenden Sie Styles über mehrere Dateien, entstehen geringe Laufzeitkosten.

  • Small API Surface: Das API von StyleX besteht aus den beiden Funktionen create und props.

  • Type-Safe Styles: StyleX ist mit Flow, dem Typsystem von Facebook, umgesetzt. Aus diesem Grund verfügen alle Styles über Typinformationen, die StyleX sowohl für Flow als auch für TypeScript zur Verfügung stellt.

  • Shareable Constants: StyleX übersetzt CSS-Klassen, -Variablen und andere Identifier in JavaScript-Konstanten, sodass die Typsicherheit im Code nicht verloren geht.

  • Framework-agnostic: StyleX klingt zwar sehr nach React und funktioniert auch hervorragend damit, Sie können aber auch andere Frameworks damit verwenden.

  • Encapsulation: Alle Styles sind Klassen zugeordnet. Komplexe Selektoren werden nicht unterstützt, um die Implementierung so einfach, vorhersehbar und performant wie möglich zu halten.

  • Readability & Maintainability over Terseness: Performance und Lesbarkeit stehen ganz oben auf der Prioritätenliste von StyleX. Das Werkzeug bewegt sich nahe an den Standardbezeichnungen von CSS.

  • Modularity and Composability: StyleX versucht Styles so zu organisieren, dass sie wiederverwendbar sind und im besten Fall auch in Paketen organisiert und damit sogar zwischen Applikationen geteilt werden können.

  • Avoid global configuration: StyleX kommt ohne zusätzliche Konfiguration aus.

  • One small File over many smaller Files: StyleX erzeugt ein optimiertes CSS-Bundle, das initial geladen wird.

Diese Prinzipien klingen sinnvoll und durchdacht, doch wie sieht das Ganze in der Praxis aus? Für die CSS-in-JS-Lösung müssen Sie vor der Verwendung von StyleX das zugehörige Paket installieren. Das geschieht mit dem Kommando npm install @stylexjs/stylex. Theoretisch können Sie die dev-runtime von StyleX verwenden, die die Styles zur Laufzeit übersetzt. Hiervon rät StyleX jedoch ab. Stattdessen sollten Sie lieber das Babel-Plug-in verwenden.

 

 

Styles mit StyleX definieren und einbinden

Das API von StyleX besteht aus den beiden Funktionen create, mit der Sie die Styles definieren, und props, mit der Sie die Styles anwenden. Ein einfaches Beispiel könnte wie in Listing 2 aussehen.

Listing 2: Definition der Styles

import * as stylex from '@stylexjs/stylex';
 
const styles = stylex.create({
  headline: {
    color: 'red',
    textDecoration: {
      default: 'none',
      ':hover': 'underline',
    },
  },
});

Der create-Funktion übergeben Sie ein Objekt, in der Sie die verschiedenen Styles definieren können. Hier sehen Sie, dass es eine headline-Definition gibt. Deren Schriftfarbe ist rot, und wenn Sie die Maus über das Element bewegen, wird es unterstrichen. Im einfachsten Fall arbeiten Sie also wie in regulärem CSS mit Deklarationen, also mit Schlüsseln und Werten. Wo CSS auf Eigenschaftsnamen mit Bindestrichen setzt, arbeitet StyleX mit der CamelCase-Schreibweise. Der Grund dafür ist, dass Bindestriche in Eigenschaftsnamen nur erlaubt sind, wenn Sie sie in Anführungszeichen setzen würden. Noch mehr Kontrolle erlaubt Ihnen StyleX, wenn Sie für eine Eigenschaft ein Objekt als Wert angeben. In diesem Fall können Sie beispielsweise Pseudo-Klassen unterstützen. Zusätzlich dazu können Sie Pseudo-Elemente und Media Queries in Ihre Styles einbauen.

Haben Sie die Styles definiert, können Sie sie mit der props-Funktion in ein Element integrieren:

<h1 {...stylex.props(styles.headline)}>Hallo StyleX</h1>;

Sie können nicht nur einen Style, wie hier im Beispiel, übergeben, sondern beliebig viele. Damit können Sie einen Basis-Style definieren und diesen bei Bedarf teilweise überschreiben. Die zuletzt genannten Styles überschreiben dabei die vorhergehenden.

Aus den Style-Definitionen macht StyleX reguläre CSS-Klassendefinitionen, die es in einem separaten CSS-Bundle ablegt. Für die Anwendung der Styles integriert das Werkzeug die zugehörigen Klassen in die jeweiligen Elemente.

Weitere Features von StyleX

Neben diesen grundlegenden Features, die wir von jedem Styling-Werkzeug erwarten, bietet StyleX noch einige weitere Komfortfeatures. Alles nichts, was StyleX gravierend von der Konkurrenz abheben würde, aber insgesamt eine recht runde Sache.

Parametrisierung

Sie können die Styles, die Sie mit der create-Funktion erstellen, auch als Funktionen definieren. Damit können Sie ähnliche Styles in einem Block definieren und durch die Parameter das Verhalten steuern. Im folgenden Beispiel in Listing 3 sehen Sie den line-Style als Funktion implementiert, der Sie bei der Einbindung eine Hintergrundfarbe übergeben können.

Listing 3: Parametrisierte Styles

const styles = stylex.create({
  line: (color: string) => ({
    backgroundColor: color,
  }),
});
 
<div {...stylex.props(styles.line('red'))}>line 1</div>
<div {...stylex.props(styles.line('green'))}>line 2</div>

Variablen und Theming

Das API von StyleX ist zwar übersichtlich, besteht jedoch nicht nur aus den beiden Funktionen create und props. Mit einer weiteren Funktion, der defineVars-Funktion, können Sie Variablen definieren. Diese Datei muss eine bestimmte Endung aufweisen. Zulässig sind beispielsweise .style.ts oder style.tsx. Nutzen können Sie diese Variablen dann in Ihren Style-Definitionen. Das in Listing 4 dargestellte Beispiel definiert eine Primärfarbe und einen Standardabstand und wendet sie dann auf ein h1-Element an.

Listing 4: Verwendung von Variablen

import * as stylex from '@stylexjs/stylex';
export const colors = stylex.defineVars({
  primary: 'hotpink',
});
 
import { colors } from './tokens.stylex';
const styles = stylex.create({
  heading: {
    color: colors.primary,
  },
});

Noch einen Schritt weiter geht der Theme-Support von StyleX mit der createTheme-Funktion. Hier können Sie eine Gruppe von Variablen übergeben, die Sie mit defineVars definiert haben, und Standardwerte sowie Theme-spezifische Werte definieren.

Fazit

Für die Community ist StyleX ein brandneues Werkzeug, das einen ähnlichen Weg wie andere CSS-in-JS-Werkzeuge einschlägt, und doch hat es seine Besonderheiten. StyleX konzentriert sich auf Einfachheit und Performance. Es senkt die Einstiegshürde so weit, dass Sie innerhalb kürzester Zeit mit der Arbeit loslegen können. Die Integration in React ist hervorragend, aber auch mit Next.js lässt sich StyleX problemlos verwenden. Ob es sich gegen die etablierte Konkurrenz wie Styled-Components oder Emotion durchsetzen und sich im Markt etablieren kann, wird die Zeit zeigen.

Immer auf dem Laufenden bleiben!
Alle News & Updates: